import datetime
import backtrader as bt


class StrategyClass(bt.Strategy):
    params = dict(
        half=1000,
    )

    def _reset(self, daytemp=None):
        self.daytemp = daytemp or (self.data.open[0], self.data.close[0], self.data.high[0], self.data.low[0])
        self.over = False
        self.sell1 = True
        self.sell2 = True
        self.buy1 = True
        self.buy2 = True
        d = self.datetime.datetime() if len(self) > 0 else datetime.datetime.now()
        self.validtime = datetime.datetime(d.year, d.month, d.day, 14, 49)

    def __init__(self):
        self.currTrade = (None, 0)
        self._reset((0, 0, 0, 0))
        # 20日均线
        self.sma20 = bt.ind.SMA(self.data1.close, period=20)
        # 5日均线
        self.sma5 = bt.ind.SMA(self.data1.close, period=5)

    def log(self, txt, dt=None):
        dt = dt or self.data.datetime.datetime()
        print("%s %s" % (dt.isoformat(), txt))

    def notify_order(self, order):
        if order.status in [bt.Order.Submitted, bt.Order.Accepted]:
            return  # Await further notifications

        if order.status == order.Completed:
            if order.isbuy():
                buytxt = 'BUY COMPLETE, %.2f, size:%s, pos: %s' % (
                    order.executed.price, order.executed.size, self.position.size)
                self.log(buytxt, bt.num2date(order.executed.dt))
            else:
                selltxt = 'SELL COMPLETE, %.2f' % order.executed.price
                self.log(selltxt, bt.num2date(order.executed.dt))
        elif 'log' in order.info:
            self.log("盘中未能出现" + order.info['log'])
        elif order.status in [order.Expired, order.Canceled, order.Margin]:
            self.log('%s , %s' % (order.Status[order.status], order))
            pass  # Simply log

        # Allow new orders
        self.orderid = None

    def notify_trade(self, trade):
        if trade.isclosed:
            self.log('TRADE PROFIT, GROSS %.2f, NET %.2f \n' %
                     (trade.pnl, trade.pnlcomm))

        elif trade.justopened:
            self.currTrade = (trade, trade.value)
            self.log('TRADE OPENED, SIZE %2d, PRICE %s, VALUE %s' % (trade.size, trade.price, trade.value))

    def _dayend(self, m=[5, 10]):
        d = self.datetime.datetime()
        t = 60 - d.minute
        return d.hour == 14 and (t in m)

    def _red(self):
        return self.daytemp[0] < self.daytemp[1]

    def _greed(self):
        return self.daytemp[0] > self.daytemp[1]

    def next(self):
        if len(self) == 1 or self.datetime.datetime().date() != self.datetime.datetime(-1).date():
            self._reset()
        else:
            self.daytemp = (self.daytemp[0], self.data.close[0],
                            self.daytemp[2] if self.daytemp[2] > self.data.high[0] else self.data.high[0],
                            self.daytemp[3] if self.daytemp[3] < self.data.low[0] else self.data.low[0]
                            )

        #         if self._dayend([0]):
        #             pass
        if self.over:
            # 今日已完结
            return

        if self._dayend():  # 尾盘前十分钟
            if not self.position:
                # 4、空仓时，收盘前10分钟，收红盘，收盘价大于5日线，买入，其它情况不买
                if self._red() and self.daytemp[1] > self.sma5[0]:
                    # TODO 空仓买入
                    self.log("4、空仓时，收盘前10分钟，收红盘，收盘价大于5日线，买入")
                    self.buy(size=self.p.half)
                self.over = True
            else:
                # 3、收盘前10分钟，收绿盘价格<20日线，清仓，其它情况持仓
                if self._greed() and self.daytemp[1] < self.sma20[0]:
                    self.log("3、收盘前10分钟，收绿盘价格<20日线，清仓")
                    self.close()
                    self.over = True
                    return
                # 7、每日监测收益，超过20%后，如果出现当日最低跌幅达到7个点时，清仓。
                if ((self.currTrade[0].pnlcomm - self.currTrade[1]) / self.currTrade[1] > 0.2 and
                        (self.data1.close[-1] - self.daytemp[3]) / self.data1.close[-1] > 0.07):
                    self.log("7、每日监测收益，超过20%后，如果出现当日最低跌幅达到7个点时，清仓")
                    self.close()
                    self.over = True
                    return
                if self._dayend([5]) and self.position.size < self.p.half:
                    # 尾盘五分钟，仓位回归
                    upover = (self.data.close[0] - self.data1.close[-1] + 0.01) / self.data.close[-1] > 0.1
                    downover = (self.data1.close[-1] - self.data.close[0] + 0.01) / self.data.close[-1] > 0.1
                    if not (upover or downover):
                        # 且非涨跌停
                        self.log("尾盘仓位回归")
                        self.order_target_size(target=self.p.half)
                        self.over = True
                        return

        elif self.position.size > 0:
            if self.sell2 and (self.data.close[0] - self.data1.close[-1] + 0.01) / self.data.close[-1] > 0.1:
                # 涨停
                self.sell2 = False
                self.log("涨停，全卖，记录卖出价2；")
                size = self.position.size
                order = self.sell(size=size)
                self.buy(size=size, exectype=bt.Order.Limit, price=self.data.close[0] * (1 - 0.03),
                         valid=self.validtime, log="出现比价1低三个点时")
            if self.sell1 and (self.data.close[0] - self.data1.close[-1] + 0.01) / self.data.close[-1] >= 0.05:
                self.sell1 = False
                if self.position.size > self.p.half / 2:
                    self.log("开盘后涨5个点，卖一半，记录卖出价1；")
                    order = self.order_target_size(target=self.p.half / 2)
                    self.buy(size=self.p.half / 2, exectype=bt.Order.Limit, price=self.data.close[0] * (1 - 0.04),
                             valid=self.validtime, log="出现比价2低4个点")
                pass
            if self.buy2 and (self.data1.close[-1] - self.data.close[0] + 0.01) / self.data.close[-1] > 0.1:
                # 跌停
                self.buy2 = False
                if self.position.size < self.p.half * 2:
                    self.log("跌停买入再买1/4，标注买入价格2；")
                    order = self.order_target_size(target=self.p.half * 2)
                    self.sell(size=self.p.half / 2, exectype=bt.Order.Limit, price=self.data.close[0] * (1 + 0.03),
                              valid=self.validtime, log="比价2高三个点时")
            if self.buy1 and (self.data1.close[-1] - self.data.close[0] + 0.01) / self.data.close[-1] > 0.05:
                self.buy1 = False
                if self.position.size < self.p.half * 3 / 2:
                    self.log("开盘后跌5个点，买仓位1/4，记录买入价格1；")
                    order = self.order_target_size(target=self.p.half * 3 / 2)
                    self.sell(size=self.p.half / 2, exectype=bt.Order.Limit, price=self.data.close[0] * (1 + 0.03),
                              valid=self.validtime, log="出现比价1高三个点时")
